/*--------------------------------------------- Noble Steed Engine--------------------------------------*
Authors : Daniel Randle, Alex Bourne
Date Created : Mar 16 2013

File:
	nsshaderset.cpp

Description:
	This file contains the definition for the NSShaderSet class and any associated functions that help
	the ol' girl out
*-----------------------------------------------------------------------------------------------------*/

#include <nsshaderset.h>
#include <nsobjectset.h>
#include <logfile.h>
#include <sstream>

#ifdef DEBUG
#include <debug.h>
#endif

/*----------------------------*
|   class NSShaderSet BEGINS  |
*-----------------------------*/

NSShaderSet::NSShaderSet(NSObjectSet * objects):objectSet(objects)
{
	LogFile("Creating shader set...");
}

NSShaderSet::~NSShaderSet()
{
	LogFile("Deleting shaders in shader set...");
	while (shaders.begin() != shaders.end())
	{
		delete shaders.back();
		shaders.pop_back();
	}
	LogFile("ShaderSet Deleted");
}

void NSShaderSet::addShader(NSShader * shader)
{
	shaders.push_back(shader);
}

NSShader * NSShaderSet::addShader(NSShader::ShaderProgType type, 
	const std::string & _shaderID, 
	const std::string & fragmentFileName, 
	const std::string & vertexFileName, 
	const std::string & geometryFileName, 
	const std::string & shaderDirectory)
{
	NSShader * shader = NULL;
	switch (type)
	{
	case (NSShader::BASE):
		shader = new NSShader(_shaderID,fragmentFileName,vertexFileName,geometryFileName,shaderDirectory);
		break;
	case (NSShader::LIGHT):
		shader = new NSLightShader(_shaderID,fragmentFileName,vertexFileName,geometryFileName,shaderDirectory);
		break;
	case (NSShader::SHADOW):
		shader = new NSShadowShader(_shaderID,fragmentFileName,vertexFileName,geometryFileName,shaderDirectory);
		break;
	case (NSShader::PICKING):
		shader = new NSPickingShader(_shaderID,fragmentFileName,vertexFileName,geometryFileName,shaderDirectory);
		break;
	}
	if (shader != NULL)
		addShader(shader);
	else
		LogFile("ERROR : Tried to create a shader with unknown shader type");
	return shader;
}

bool NSShaderSet::removeShader(NSShader * shader)
{
	if (shader->objectsUsing() > 0)
	{
		objectSet->removeObjectsShader(shader);
		removeShader(shader);
	}

	std::vector<NSShader*>::iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		if (*iter == shader)
		{
			LogFile("Deleting shader ID: " + (*iter)->getShaderID());
			delete (*iter);
			iter = shaders.erase(iter);
			LogFile("Successfully deleted shader");
			return true;
		}
		++iter;
	}
	LogFile("Unable to delete shader ID: " + (*iter)->getShaderID());
	return false;
}

bool NSShaderSet::removeShader(unsigned int progID)
{
	return removeShader(getShader(progID));
}

bool NSShaderSet::removeShader(const std::string & shaderID)
{
	 return removeShader(getShader(shaderID));
}


NSShader * NSShaderSet::getShader(unsigned int progID)
{
	std::stringstream strst;
	std::vector<NSShader*>::iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		if ((*iter)->getProgID() == progID)
			return *iter;
		++iter;
	}
	strst << "Unable to get shader with prog ID: " << progID;
	LogFile l(strst);
	return NULL;
}

NSShader * NSShaderSet::getShader(const std::string & shaderID)
{
	std::vector<NSShader*>::iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		if (*iter == NULL)
			return NULL;
		if ((*iter)->getShaderID() == shaderID)
		{
			return *iter;
		}
		++iter;
	}
	LogFile("Unable to get shader with shader ID: " +shaderID);
	return NULL;
}


void NSShaderSet::setAllUniforms(const char * variableName, const NSMatrix4Df & data) const
{
	std::vector<NSShader*>::const_iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		(*iter)->enable();
		(*iter)->setUniform(variableName, data);
		++iter;
	}
}

void NSShaderSet::setAllUniforms(const char * variableName, const NSMatrix3Df & data) const
{
	std::vector<NSShader*>::const_iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		(*iter)->enable();
		(*iter)->setUniform(variableName, data);
		++iter;
	}
}

void NSShaderSet::setAllUniforms(const char * variableName, const NSVec4Df & data) const
{
	std::vector<NSShader*>::const_iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		(*iter)->enable();
		(*iter)->setUniform(variableName, data);
		++iter;
	}
}

void NSShaderSet::setAllUniforms(const char * variableName, const NSVec3Df & data) const
{
	std::vector<NSShader*>::const_iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		(*iter)->enable();
		(*iter)->setUniform(variableName, data);
		++iter;
	}
}

void NSShaderSet::setAllUniforms(const char * variableName, const NSVec2Df & data) const
{
	std::vector<NSShader*>::const_iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		(*iter)->enable();
		(*iter)->setUniform(variableName, data);
		++iter;
	}
}

void NSShaderSet::setAllUniforms(const char * variableName, float data) const
{
	std::vector<NSShader*>::const_iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		(*iter)->enable();
		(*iter)->setUniform(variableName, data);
		++iter;
	}
}

void NSShaderSet::setAllUniforms(const char * variableName, int data) const
{
	std::vector<NSShader*>::const_iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		(*iter)->enable();
		(*iter)->setUniform(variableName, data);
		++iter;
	}
}

void NSShaderSet::setAllUniforms(const char * variableName, unsigned int data) const
{
	std::vector<NSShader*>::const_iterator iter = shaders.begin();
	while (iter != shaders.end())
	{
		(*iter)->enable();
		(*iter)->setUniform(variableName, data);
		++iter;
	}
}

NSShaderSet::Iterator NSShaderSet::begin()
{
	return shaders.begin();
}

NSShaderSet::Iterator NSShaderSet::end()
{
	return shaders.end();
}